﻿using System;
using System.IO;
using System.Reflection;
using System.Resources;
using System.Threading;
using Inovout.FileStorage;
using Castle.Core.Logging;

namespace Inovout
{
    internal class ManifestResource : FileEntity
    {
        private static readonly ILogger log = Logger.Create(typeof(ManifestResource));
        
        private Assembly assembly; 
        private string baseResourceName;
        private string language;
        internal ManifestResource(Assembly assembly, string baseResourceName)
            :this(assembly,baseResourceName,Thread.CurrentThread.CurrentUICulture.ToString())
        { 
        }
        internal ManifestResource(Assembly assembly, string baseResourceName, string language)
        {
            ArgumentGuard.IsNotNull(assembly, "assembly");
            ArgumentGuard.IsNotNullOrEmptyString(baseResourceName, "baseResourceName");
            ArgumentGuard.IsNotNullOrEmptyString(language, "language");
            this.assembly = assembly;
            this.baseResourceName = baseResourceName;
            this.language = language;

            Load();           
        }
        private ResourceManager resourceManager;
        protected virtual void Load()
        {
        	string logMessage = "Loading resources " + baseResourceName + "." + language + ": ";
			    //资源文件可包含在主程序集中，也可存在于附属程序集中。
         		if (assembly.GetManifestResourceInfo(baseResourceName + "." + language + ".resources") != null) 
                {
                    log.Info(logMessage + " loading from main assembly or satellite assembly.");
					resourceManager = new ResourceManager(baseResourceName + "." + language, assembly);
				}
                else if (language.IndexOf('-') > 0
                           && assembly.GetManifestResourceInfo(baseResourceName + "." + language.Split('-')[0] + ".resources") != null)
                {
                    log.Info(logMessage + " loading from main assembly or satellite assembly(no country match).");
                    resourceManager = new ResourceManager(baseResourceName + "." + language.Split('-')[0], assembly);
                }
                else
                {
                    //也可直接通过静态文件获取。
                   resourceManager = TrySatellite(language);
                    if (resourceManager == null && language.IndexOf('-') > 0)
                    {
                        resourceManager = TrySatellite(language.Split('-')[0]);
                    }
                }
                if (resourceManager == null)
                {
                    log.Warn(logMessage + "NOT FOUND");

                    if (assembly.GetManifestResourceInfo(baseResourceName + ".resources") == null)
                    {
                        Exception missingManifestResourceException = new MissingManifestResourceException(string.Format("主程序集{0}不包含非特定区域性的资源({1})，而由于缺少相应的附属程序集，这些资源又是必需的。", assembly.FullName, baseResourceName));
                        log.Error(missingManifestResourceException.Message, missingManifestResourceException);
                        throw missingManifestResourceException;
                    }
                    else
                    {
                        log.Info("Loading resources " + baseResourceName + ": " + " loading from main assembly.");
                        resourceManager = new ResourceManager(baseResourceName, assembly);
                    }
                }
          

        }
        private ResourceManager TrySatellite(string currentLanguage)
        {
            string fileName = Path.GetFileNameWithoutExtension(assembly.Location) + ".resources.dll";
            fileName = Path.Combine(Path.Combine(Path.GetDirectoryName(assembly.Location), currentLanguage), fileName);
            if (File.Exists(fileName))
            {
                log.Info("Loging resources " + baseResourceName + " loading from satellite " + language);
                return new ResourceManager(baseResourceName, Assembly.LoadFrom(fileName));
            }
            else
            {
                return null;
            }
         
        }
    }
}
